package com.smart.common.utils;

import com.smart.common.callback.MethodCallback;
import org.apache.commons.beanutils.PropertyUtils;

import java.util.*;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.function.BiConsumer;

/**
 * List工具类
 *
 * @author ThinkGem
 * @version 2015-1-23
 */
@SuppressWarnings("rawtypes")
public class ListUtil extends org.apache.commons.collections.ListUtils {

    /**
     * 是否包含字符串
     *
     * @param str  验证字符串
     * @param list 字符串组
     * @return 包含返回true
     */
    public static boolean inString(String str, List<String> list) {
        if (str != null && list != null) {
            for (String s : list) {
                if (str.equals(StringUtil.trim(s))) {
                    return true;
                }
            }
        }
        return false;
    }

    /**
     * 是否包含字符串
     *
     * @param list1 验证字符串组
     * @param list2 字符串组
     * @return 包含返回true
     */
    public static boolean inString(List<String> list1, List<String> list2) {
        if (list1 != null && list2 != null) {
            for (String s : list1) {
                if (s != null) {
                    for (String s2 : list2) {
                        if (StringUtil.trim(s).equals(StringUtil.trim(s2))) {
                            return true;
                        }
                    }
                }
            }
        }
        return false;
    }

    public static <E> ArrayList<E> newArrayList() {
        return new ArrayList<>();
    }

    @SafeVarargs
    public static <E> ArrayList<E> newArrayList(E... elements) {
        ArrayList<E> list = new ArrayList<>(elements.length);
        Collections.addAll(list, elements);
        return list;
    }

    public static <E> ArrayList<E> newArrayList(Iterable<? extends E> elements) {
        return (elements instanceof Collection) ? new ArrayList<>(cast(elements))
                : newArrayList(elements.iterator());
    }

    public static <E> ArrayList<E> newArrayList(Iterator<? extends E> elements) {
        ArrayList<E> list = newArrayList();
        addAll(list, elements);
        return list;
    }

    public static <E> LinkedList<E> newLinkedList() {
        return new LinkedList<>();
    }

    public static <E> LinkedList<E> newLinkedList(Iterable<? extends E> elements) {
        LinkedList<E> list = newLinkedList();
        addAll(list, elements);
        return list;
    }

    public static <E> CopyOnWriteArrayList<E> newCopyOnWriteArrayList() {
        return new CopyOnWriteArrayList<>();
    }

    public static <E> CopyOnWriteArrayList<E> newCopyOnWriteArrayList(Iterable<? extends E> elements) {
        Collection<? extends E> elementsCollection = (elements instanceof Collection)
                ? cast(elements) : newArrayList(elements);
        return new CopyOnWriteArrayList<>(elementsCollection);
    }

    private static <T> Collection<T> cast(Iterable<T> iterable) {
        return (Collection<T>) iterable;
    }

    private static <T> boolean addAll(Collection<T> addTo, Iterator<? extends T> iterator) {
        boolean wasModified = false;
        while (iterator.hasNext()) {
            wasModified |= addTo.add(iterator.next());
        }
        return wasModified;
    }

    public static <T> boolean addAll(Collection<T> addTo, Iterable<? extends T> elementsToAdd) {
        if (elementsToAdd instanceof Collection) {
            Collection<? extends T> c = cast(elementsToAdd);
            return addTo.addAll(c);
        }
        return addAll(addTo, elementsToAdd.iterator());
    }

    /**
     * 提取集合中的对象的两个属性(通过Getter函数), 组合成Map.
     *
     * @param collection        来源集合.
     * @param keyPropertyName   要提取为Map中的Key值的属性名.
     * @param valuePropertyName 要提取为Map中的Value值的属性名.
     */
    @SuppressWarnings("unchecked")
    public static Map extractToMap(final Collection collection, final String keyPropertyName,
                                   final String valuePropertyName) {
        Map map = new HashMap(collection.size());
        try {
            for (Object obj : collection) {
                map.put(PropertyUtils.getProperty(obj, keyPropertyName),
                        PropertyUtils.getProperty(obj, valuePropertyName));
            }
        } catch (Exception e) {
            throw ReflectUtil.convertReflectionExceptionToUnchecked("", e);
        }
        return map;
    }

    /**
     * 提取集合中的对象的一个属性(通过Getter函数), 组合成List.
     *
     * @param collection   来源集合.
     * @param propertyName 要提取的属性名.
     */
    @SuppressWarnings("unchecked")
    public static <T> List<T> extractToList(final Collection collection, final String propertyName) {
        if (collection == null) {
            return newArrayList();
        }
        List list = new ArrayList(collection.size());
        try {
            for (Object obj : collection) {
                list.add(PropertyUtils.getProperty(obj, propertyName));
            }
        } catch (Exception e) {
            throw ReflectUtil.convertReflectionExceptionToUnchecked("", e);
        }
        return list;
    }

    /**
     * 提取集合中的对象的一个属性(通过Getter函数), 组合成List.
     *
     * @param collection   来源集合.
     * @param propertyName 要提取的属性名.
     * @param prefix       符合前缀的信息(为空则忽略前缀)
     * @param isNotBlank   仅包含不为空值(空字符串也排除)
     */
    public static List<String> extractToList(final Collection collection, final String propertyName,
                                             final String prefix, final boolean isNotBlank) {
        List<String> list = new ArrayList<>(collection.size());
        try {
            for (Object obj : collection) {
                String value = (String) PropertyUtils.getProperty(obj, propertyName);
                if (StringUtil.isBlank(prefix) || StringUtil.startsWith(value, prefix)) {
                    if (isNotBlank) {
                        if (StringUtil.isNotBlank(value)) {
                            list.add(value);
                        }
                    } else {
                        list.add(value);
                    }
                }
            }
        } catch (Exception e) {
            throw ReflectUtil.convertReflectionExceptionToUnchecked("", e);
        }
        return list;
    }

    /**
     * 提取集合中的对象的一个属性(通过Getter函数), 组合成由分割符分隔的字符串.
     *
     * @param collection   来源集合.
     * @param propertyName 要提取的属性名.
     * @param separator    分隔符.
     */
    public static String extractToString(final Collection collection, final String propertyName, final String separator) {
        List list = extractToList(collection, propertyName);
        return StringUtil.join(list, separator);
    }

    /**
     * 转换Collection所有元素(通过toString())为String, 中间以 separator分隔。
     */
    public static String convertToString(final Collection collection, final String separator) {
        return StringUtil.join(collection, separator);
    }

    /**
     * 转换Collection所有元素(通过toString())为String, 每个元素的前面加入prefix，后面加入postfix，如<div>my-message</div>。
     */
    public static String convertToString(final Collection collection, final String prefix, final String postfix) {
        StringBuilder builder = new StringBuilder();
        for (Object o : collection) {
            builder.append(prefix).append(o).append(postfix);
        }
        return builder.toString();
    }

    /**
     * 判断是否为空.
     */
    public static boolean isEmpty(Collection collection) {
        return (collection == null || collection.isEmpty());
    }

    /**
     * 判断是否为不为空.
     */
    public static boolean isNotEmpty(Collection collection) {
        return !(isEmpty(collection));
    }

    /**
     * 取得Collection的第一个元素，如果collection为空返回null.
     */
    public static <T> T getFirst(Collection<T> collection) {
        if (isEmpty(collection)) {
            return null;
        }
        return collection.iterator().next();
    }

    /**
     * 获取Collection的最后一个元素 ，如果collection为空返回null.
     */
    public static <T> T getLast(Collection<T> collection) {
        if (isEmpty(collection)) {
            return null;
        }
        //当类型为List时，直接取得最后一个元素 。
        if (collection instanceof List) {
            List<T> list = (List<T>) collection;
            return list.get(list.size() - 1);
        }
        //其他类型通过iterator滚动到最后一个元素.
        Iterator<T> iterator = collection.iterator();
        while (true) {
            T current = iterator.next();
            if (!iterator.hasNext()) {
                return current;
            }
        }
    }

    /**
     * 返回a+b的新List.
     */
    public static <T> List<T> unionCollection(final Collection<T> a, final Collection<T> b) {
        List<T> result = new ArrayList<>(a);
        result.addAll(b);
        return result;
    }

    /**
     * 返回a-b的新List.
     */
    public static <T> List<T> subtractCollection(final Collection<T> a, final Collection<T> b) {
        List<T> list = new ArrayList<>(a);
        for (T element : b) {
            list.remove(element);
        }
        return list;
    }

    /**
     * 返回a与b的交集的新List.
     */
    public static <T> List<T> intersectionCollection(Collection<T> a, Collection<T> b) {
        List<T> list = new ArrayList<>();
        for (T element : a) {
            if (b.contains(element)) {
                list.add(element);
            }
        }
        return list;
    }

    /**
     * 列表分页方法
     *
     * @param list         数据源
     * @param pageSize     每页大小
     * @param pageCallback 分页回调，返回当前页的数据及分页信息（pageList, pageNo, pageSize）
     * @author ThinkGem
     */
    public static <T> void pageList(List<T> list, int pageSize, MethodCallback pageCallback) {
        if (list != null && !list.isEmpty()) {

            int count = list.size(), pageNo = 1;
            int totalPage = (count + pageSize - 1) / pageSize;

            while (true) {
                // 执行回调，分页后的数据
                List<T> pageList = getPageList(list, pageNo, pageSize, totalPage);
                if (!pageList.isEmpty()) {
                    pageCallback.execute(pageList, pageNo, pageSize, totalPage);
                }
                // 如果为最后一页，则跳出循环
                if (pageNo >= totalPage) {
                    break;
                }
                // 页数加一继续下一页
                pageNo++;
            }
        }
    }

    /**
     * 列表分页方法
     *
     * @param list      源数据
     * @param pageNo    当前页码
     * @param pageSize  每页显示条数
     * @param totalPage 总页码数
     * @author ThinkGem
     */
    public static <T> List<T> getPageList(List<T> list, int pageNo, int pageSize, int totalPage) {
        int fromIndex = 0; // 从哪里开始截取
        int toIndex = 0; // 截取几个
        if (list == null || list.isEmpty()) {
            return new ArrayList<>();
        }
        // 当前页小于或等于总页数时执行
        if (pageNo <= totalPage && pageNo != 0) {
            fromIndex = (pageNo - 1) * pageSize;
            if (pageNo == totalPage) {
                toIndex = list.size();
            } else {
                toIndex = pageNo * pageSize;
            }
        }
        return list.subList(fromIndex, toIndex);
    }

    /**
     * 本地列表排序
     *
     * @param list    需要排序的列表
     * @param orderBy 排序的键值（如：id desc）
     * @author ThinkGem
     */
    public static <T> List<T> listOrderBy(List<T> list, String orderBy) {
        if (list != null && StringUtil.isNotBlank(orderBy)) {
            final String[] ss = orderBy.trim().split(" ");
            final String t = ss.length == 2 ? ss[1] : "asc";
            list.sort((o1, o2) -> {
                String s1, s2;
                if (o1 instanceof Map) {
                    s1 = ObjectUtil.toString(((Map) o1).get(ss[0]));
                    s2 = ObjectUtil.toString(((Map) o2).get(ss[0]));
                } else {
                    s1 = ObjectUtil.toString(ReflectUtil.invokeGetter(o1, ss[0]));
                    s2 = ObjectUtil.toString(ReflectUtil.invokeGetter(o2, ss[0]));
                }
                if ("asc".equalsIgnoreCase(t)) {
                    return s1.compareTo(s2);
                } else {
                    return s2.compareTo(s1);
                }
            });
        }
        return list;
    }

    /**
     * foreach添加索引
     *
     * @param elements 集合
     * @param action   参数
     * @param <E>      方法
     */
    public static <E> void forEach(Iterable<? extends E> elements, BiConsumer<Integer, ? super E> action) {
        Objects.requireNonNull(elements);
        Objects.requireNonNull(action);
        int index = 0;
        for (E element : elements) {
            action.accept(index++, element);
        }
    }

    public static void main(String[] args) {
        List<String> a = newArrayList("a","b","c","d","e","f");
        List<String> b = newArrayList("d","b", "e");
        List<String> strings = subtractCollection(a, b);
        strings.forEach(System.out::println);
    }
}
